#include "Structures.fxh"
#include "Lighting.fxh"

#define SAMPLE_COUNT 15

cbuffer Samples {
  uniform float2 SampleOffsets[SAMPLE_COUNT];
  uniform float SampleWeights[SAMPLE_COUNT];
};

cbuffer PerFrame {
	uniform float4x4 WVP; //WorldViewProjection
	uniform float4x4 World;
	uniform float4x4 WorldIT; //WorldInverseTranspose
	uniform float3 EyePos;
};

//CBuffer for lighting values
cbuffer Lighting {
	uniform float3 GlobalAmbient : GLOBALAMBIENT = { 0.0f, 0.0f, 0.0f };
	uniform Light Lights[4] : LIGHTLIST;
	uniform int NumLights : LIGHTCOUNT = 0;
};

//CBuffer for material properties
cbuffer PerMaterial {
	uniform float3 MatDiffuse = { 1.0f, 1.0f, 1.0f};
	uniform float3 MatAmbient = { 0.2f, 0.2f, 0.2f};
	uniform float3 MatEmissive = { 1.0f, 1.0f, 1.0f};
	uniform float3 MatSpecular = { 0.0f, 0.0f, 0.0f};
	uniform float MatShininess = 16.0f;
	uniform float Alpha = 1.0f;
};

cbuffer BoolProperties {
  uniform bool UseEmissiveMap = true;
};

uniform Texture2D DiffuseMap;
uniform SamplerState DiffuseMapSampler {
	Filter = ANISOTROPIC;
	AddressU = Wrap;
	AddressV = Wrap;
};

uniform Texture2D EmissiveMap;
uniform SamplerState EmissiveMapSampler {
	Filter = ANISOTROPIC;
	AddressU = Wrap;
	AddressV = Wrap;
};


VSOutputNmTx VS_TextureGlow(VSInputNmTx input) {
	float4 pos = float4(input.Position, 1.0);

	VSOutputNmTx output;
	output.PositionPS = mul(pos, WVP);
	output.PositionWS = mul(pos, World).xyz;
	output.Normal = normalize(mul(float4(input.Normal, 0.0), WorldIT).xyz);
	output.TexCoord = input.TexCoord;
	return output;
}

float4 PS_TextureGlow(VSOutputNmTx input) : SV_TARGET {
	//Individual light contribs from each light
	float3 lightContribs = float3(0,0,0);

	//Get the diffuse map color
	float4 albedo = DiffuseMap.Sample(DiffuseMapSampler, input.TexCoord);
	
	//Get emissive map color
  float4 emissive = float4(MatEmissive, 1.0f);
	if(UseEmissiveMap) {
		emissive *= EmissiveMap.Sample(EmissiveMapSampler, input.TexCoord);
	}

	Material mat;
	mat.Ambient = MatAmbient;
	mat.Diffuse = MatDiffuse;
	mat.Specular = MatSpecular;
	mat.Shininess = MatShininess;

	//Calculate the V vector for specular highlights
	float3 V = normalize(EyePos - input.PositionWS);

	float3 normal = input.Normal;
	float3 pos = input.PositionWS;

	for(int i = 0; i < NumLights; i++) {
		Light l = Lights[i];
		LightResult result = ComputeSingleLight(l, pos, normal, V, mat);
		float3 diffuse = (result.Diffuse + result.Ambient) * albedo.rgb;
		float3 specular = result.Specular;
		lightContribs += ComputeAttenuation(pos, l) * SpotEffect(pos, l) * (diffuse + specular);
	}

	float3 color = (MatAmbient * GlobalAmbient) + emissive + lightContribs;

	return float4(color, Alpha * albedo.a);
}

technique10 TextureGlow {
	pass Pass0 {
		SetGeometryShader(0);
		SetVertexShader(CompileShader(vs_4_0, VS_TextureGlow()));
		SetPixelShader(CompileShader(ps_4_0, PS_TextureGlow()));
	}
}



VSOutputTx VS_Blur(VSInputTx input) {
  VSOutputTx output;
  output.PositionPS = float4(input.Position, 1.0f);
  output.TexCoord = input.TexCoord;
  return output;
}


float4 PS_Blur(VSOutputTx input)  : SV_TARGET {
  float4 color = float4(0,0,0,0);
  
  for(int i = 0; i < SAMPLE_COUNT; i++) {
    color += EmissiveMap.Sample(EmissiveMapSampler, input.TexCoord + SampleOffsets[i]) * SampleWeights[i];
  }
  
  return color;
}


technique10 GaussianBlur {
  pass pass0 {
    SetGeometryShader(0);
		SetVertexShader(CompileShader(vs_4_0, VS_Blur()));
		SetPixelShader(CompileShader(ps_4_0, PS_Blur()));
  }
}